﻿using System.IO;
using System.Linq;
using EnvDTE;
using EnvDTE80;
using Expect.Core;
using Microsoft.VisualStudio.Shell;

namespace Expect.VisualStudio.Extensions.Commands.Handlers
{    
    class CreateContainerMethod : UnresolvedFixtureCommand
    {
        public CreateContainerMethod(IExpectPackage pkg)
            : base(pkg, CommandIDs.cmdidCreateContainerMethod)
        {
        }

        public override string DisplayText
        {
            get
            {
                return "Container => create method";
            }
        }

        public override void ExecuteCommand(SelectionResolution resolution)
        {
            var dte = (DTE2)GetVSService(typeof(Microsoft.VisualStudio.Shell.Interop.SDTE));
            var container = GetContainerCodeClass(resolution, dte);

            CodeFunction2 method = GetFixtureMethod(resolution, resolution.ClickedRow, container);

            var pt = method.GetStartPoint(vsCMPart.vsCMPartBody);

            var wnd = container.ProjectItem.Open();
            wnd.Activate();

            EditorHelper.SetCursorTo(dte, wnd, pt.Line, 0);
        }

        public static CodeFunction2 GetFixtureMethod(SelectionResolution resolution, FixtureRow row, CodeClass container)
        {
            var methodName = resolution.NameProvider.ElementName(row.NamesForFluent().ToArray());
            var methodArgs = row.ArgsForFluent().ToArray();
            return GetFixtureMethod(resolution, row, methodName, methodArgs, container);
        }

        public static CodeFunction2 GetFixtureMethod(SelectionResolution resolution, FixtureRow row, string methodName, string[] methodArgs, CodeClass container)
        {
            CodeFunction2 method = (CodeFunction2)container.AddFunction(methodName, vsCMFunction.vsCMFunctionFunction, "void", -1, vsCMAccess.vsCMAccessPublic);
            method.AddAttribute(typeof(FixtureHintAttribute).Name.Replace("Attribute", ""), "\"" + row.ToHint() + "\"", -1);

            foreach (var methodArg in methodArgs)
            {
                method.AddParameter("param_for_" + resolution.NameProvider.ElementName(methodArg), "string", method.Parameters.Count);
            }

            var pt = method.GetStartPoint(vsCMPart.vsCMPartBody);
            var ptEdit = pt.CreateEditPoint();
            ptEdit.Insert("\t\t\tthrow new NotImplementedException();");

            return method;
        }

        public static CodeClass GetContainerCodeClass(SelectionResolution resolution, EnvDTE80.DTE2 dte)
        {
            if (resolution.Context.Container == null)
            {
                return GenerateContainerCodeClass(resolution, dte);
            }

            return resolution.Context.Container.Item.FileCodeModel.CodeElements.GetClass(resolution.Context.ContainerClassName);
        }

        public static CodeClass GenerateContainerCodeClass(SelectionResolution resolution, DTE2 dte)
        {
            var fixtureClassName = resolution.NameProvider.ElementName(resolution.Fixture.Rows[0][0].Text);
            var containerFileDir = Path.GetDirectoryName(resolution.Context.FileName);
            var containerFileName = Path.Combine(containerFileDir, resolution.Context.ContainerClassName + ".cs");
            var containerNamespace = resolution.Context.ContainerClassFullName.Substring(
                0, resolution.Context.ContainerClassFullName.LastIndexOf("."));

            CodeModel cm = (CodeModel)resolution.Context.Item.ContainingProject.CodeModel;
            CodeNamespace currentnamespace = cm.AddNamespace(containerNamespace, containerFileName, -1);
            var edit = currentnamespace.GetStartPoint().CreateEditPoint();
            edit.Insert("using System;\r\n");

            object[] bases = { /*baseType.FullName*/ };
            object[] interfaces = { /*"System.IDisposable", "System.IComparable"*/ };

            CodeClass2 generatedClass = (CodeClass2)currentnamespace.AddClass("tempname", -1, bases, interfaces, vsCMAccess.vsCMAccessPublic);
            generatedClass.ClassKind = vsCMClassKind.vsCMClassKindPartialClass;
            generatedClass.Name = resolution.Context.ContainerClassName;
            
            return generatedClass;
        }

        
    }
}
